Программная синхронизация доступа к данным

При одновременном доступе нескольких пользователей к одной и той же записи в источнике данных могут возникнуть конфликты. Например, конфликты могут возникать при выполнении метода Update или Delete объекта Recordset и метода OpenDatabase объекта Workspace или DBEngine. Предотвращение конфликтов зависит от настройки Access, касающейся методов блокировки записей, режима доступа к базе данных, периодов обновления данных. Об установке этих параметров мы уже говорили в разд. "Организация совместного доступа к данным и объектам" этой главы. Более подробную информацию можно найти в справочной системе Access.

При программном доступе к совместно используемым базам данных необходимо организовать собственную обработку ошибок, появляющихся при попытке выполнить операции, которые могут привести к возникновению конфликтов. В приложении "Игра в доминирование" используется метод блокировки на уровне записей, блокируются изменяемые записи. В этом случае при возникновении конфликта самым простым решением является ожидание момента, когда заблокированная запись будет освобождена другим пользователем. Этот подход достаточно просто реализовать в процедуре на VBA, используя оператор Resume для повторного выполнения действия через некоторый интервал времени (сделав паузу). Назовем этот способ синхронизацией доступа к данным.

Рассмотрим в качестве примера синхронизации функцию отправки сервером сообщения одному из игроков (программа 16.9). Вспомогательная функция doPause, позволяющая сделать паузу в работе приложения на заданное количество секунд, приведена в программе 16.10.

Программа 16.9. Синхронизация записи изменений в источнике данных

' Послать сообщение подключенному игроку

Public Sub SendMessage(message As String, playerName As String) .

' Объявления локальных объектных переменных:

Dim db As Database

Dim rs As Recordset

Dim counter As Integer

' Определяем собственную обработку ошибок:

On Error GoTo errHandler

Set db = CurrentDb

' Открываем таблицу сообщений для игрока:

Set rs = db.OpenRecordset("Сообщения", dbOpenDynaset)

On Error GoTo 0

' Добавляем сообщение в таблицу сообщений клиента:

rs.AddNew

rs!ИмяИгрока = playerName

rs!Сообщение = message

' Обработка ошибок, возникающих при совместном доступе

' к источнику данных:

On Error GoTo tryAgain

rs.Update

On Error GoTo 0

rs.Bookmark = rs.LastModified

' Закрываем открытые объекты:

closeAHHandler:

rs.Close

endHandler:

' Очищаем объектные переменные, т. к. они больше не используются:

Set rs = Nothing

Set db = Nothing

' Завершаем работу:

Exit Sub

' Синхронизация: tryAgain:

counter = counter + 1 If counter < 400 Then

doPause 5 Resume

End If

Обработка ошибок: errHandler:

Dim errMsg As String

errMsg = "Ошибка: " & Err.Number & vbCrLf & _

"Источник: " & Err.Source & vbCrLf & _ vbCrLf & Err.Description

MsgBox errMsg, vbCritical, ERR_TITLE Resume endHandler

End Sub

Программа 16.10. Сделать паузу на заданное количество секунд в работе приложения

Public Sub doPause(seconds As Integer)

Dim var_timeStart, var_timeCurrent

Dim ftimeOut As Boolean

var_timeStart = Time() ' Время начала паузы Do

' Передать управление другим процессам операционной системы

DoEvents

var_timeCurrent = Time() ' Текущее системное время

ftimeOut = _

CDate(var timeCurrent - var timeStart) >=

CDate(TimeSerial(0, 0, seconds))

Loop Until ftimeOut End Sub